#pragma once
#include "MyGraphics.hpp"
#include <windows.h>
#include "MyImage.hpp"

enum class KeyCode {
    A, D, S, W, Space,
    Count
};

enum class MouseButton {
    Left, Right,
    Count
};

struct WindowCallbacks {
    using KeyCallback    = void(*)(KeyCode key, bool pressed);
    using MouseCallback  = void(*)(MouseButton button, bool pressed);
    using ScrollCallback = void(*)(float offset);

    KeyCallback    onKey    = nullptr;
    MouseCallback  onMouse  = nullptr;
    ScrollCallback onScroll = nullptr;
};

class Window{
    public:
        static void InitializeWindow();
        static void DestroyWindow();

        Window(const char *title, int width, int height);
        ~Window();

        void PollEvents();
        bool IsKeyPressed(KeyCode key) const;
        bool IsMousePressed(MouseButton button) const;
        void GetCursorPos(float &x, float &y) const;

        void SetCallbacks(const WindowCallbacks &callbacks);

        void DrawBuffer(Framebuffer &framebuffer);

        bool ShouldClose() const { return m_shouldClose; };
        void *GetUserData() const { return m_userData; };
        void SetUserData(void *data) { m_userData = data; };

        static float GetTime();

    private:
        void HandleKeyMessage(WPARAM virtualKey, bool pressed);
        void HandleMouseButtonMessage(MouseButton button, bool pressed);
        void HandleScrollMessage(float offset);
        static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);

        static void RegisterWindowClass();
        static void UnregisterWindowClass();

    private:
        bool m_shouldClose = false;
        void* m_userData = nullptr;

        HWND     m_handle     = nullptr;
        HDC      m_memoryDC   = nullptr;
        Image*   m_surface    = nullptr;
        HBITMAP m_hBitmap = nullptr;

        bool m_keyDown[(int)KeyCode::Count] = {};
        bool m_mouseDown[(int)MouseButton::Count] = {};

        WindowCallbacks m_callbacks;

    private:
        void CreateSurface(int width, int height);
        void PresentSurface();
};